/**
 * Created with IntelliJ IDEA.
 * User: keson
 * Date: 13-9-17
 * Time: 下午9:34
 * To change this template use File | Settings | File Templates.
 */
package bookShow

import (
	"github.com/astaxie/beego"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"strconv"
	"database/sql"
//	_ "github.com/Go-SQL-Driver/Mysql"
	"encoding/json"
	"publicClass"
)


type Rating struct {
	Max int
	NumRaters int
	Average string
	Min int
}
type Tag struct {
	Count int
	Name string
	Title string
}
type Images struct {
	Small string
	Medium string
	Large string
}
type Book struct {
	Rating Rating
	Subtitle string
	Author []string
	Pubdate string
	Tags []Tag
	Origin_title string
	Image string
	Translator []string
	Catalog string
	Pages string
	Images Images
	Alt string
	Id string
	Publisher string
	Isbn10 string
	Isbn13 string
	Title string
	Url string
	Alt_title string
	Author_intro string
	Summary string
	Price string
}
type NoneBook struct {
	Msg string
	Code int
	Request string
}


type GetBookController struct {
	beego.Controller
}

func (this *GetBookController) Get() {
	result := publicClass.Reason{ true, "" , nil }
	var err error = nil
//	data := make(map[string]interface {})
	for {
		id := this.GetString( "id" )
		fmt.Println( id )
		db , err := OpenMysql()
		if err != nil{
			break
		}
		defer db.Close()
		result = GetBookFromDB( id , db )
		db.Close()
		break
	}
	if err != nil{
		result.IsSuccess = false
		result.Reason = err.Error()
	}

	fmt.Println( result )
	res,_ := json.Marshal( result )
	this.Ctx.WriteString( res )
}



var AbsDir string = "f:/Information"
var JsonDir string = AbsDir + "/Json"
var ImagesDir string = AbsDir + "/Images"
var SmallImageDir string= ImagesDir + "/Small"
var MediumImageDir string= ImagesDir + "/Medium"
var LargeImageDir string= ImagesDir + "/Large"
var RootPath string = "https://api.douban.com/v2/book/"
var Begin int = 1000001
var End int = Begin + 1000
//var Processes int = 10
//var LengthPerProcess int = 100

func GetBooksFromDouban ( db *sql.DB ) (){
	os.MkdirAll( JsonDir , 0777 )
	os.MkdirAll( SmallImageDir , 0777 )
	os.MkdirAll( MediumImageDir , 0777 )
	os.MkdirAll( LargeImageDir , 0777 )

	for i:=Begin ; i<End ; i++ {
		IdString := strconv.Itoa(i)
		fmt.Print("Dealing " + IdString + " ... ")
		err := AddInfoFromDouban( IdString , db )
		if err != nil {
			fmt.Println( err )
			i --
			continue
		}
		fmt.Println("Done.")
	}
}
func AddInfoFromDouban ( IdString string , db *sql.DB ) error {
	var err error = nil
	fileName := JsonDir + "/" + IdString + ".json"
	Path := RootPath + IdString

	for {
		// get json string from Douban API
		jsonStr , err := GetJson( Path )
		if err != nil {
			break
		}
		// check json
		b , err := CheckJson( jsonStr )
		if !b {
			return nil
		}
		// save json to local
		err = SaveJson( fileName , jsonStr )
		if err != nil {
			break
		}
		// get json string
		book := ParseJson( jsonStr )
		if err != nil {
			break
		}
		// save images to local
		err = SavePicture( book , AbsDir)
		if err != nil {
			break
		}
		// save book to mysql
		err = SaveToMysql( book , db )
		if err != nil {
			break
		}
		break
	}
	return err
}
func GetJson( path string ) (string , error) {
	var Err error
	Err = nil
	jsonStr := ""
	for{
		rsp, err := http.Get( path )
		if err != nil {
			Err = err
			break
		}
		defer rsp.Body.Close()
		contents, err := ioutil.ReadAll( rsp.Body )
		if err != nil {
			Err = err
			break
		}
		jsonStr = string( contents )
		break
	}
	return jsonStr , Err
}
func CheckJson( jsonStr string ) ( bool, error ) {
	flag := true
	var err error = nil
	var nb NoneBook
	json.Unmarshal( []byte(jsonStr) , &nb )
	if nb.Code != 0 {
		flag = false
	}
	return flag , err
}
func SaveJson( fileName string , jsonStr string ) error {
	var Err error
	Err = nil
	for{
		file , err := os.Create( fileName )
		if err != nil {
			fmt.Println(err)
			break
		}
		defer file.Close()
		file.Write( []byte(jsonStr) )
		break
	}
	return Err
}
func OpenMysql () ( *sql.DB , error ){
	db , err := sql.Open("mysql" , "root:123456@/mydb?charset=utf8")
	if err != nil {
		return db , err
	}
	return db , nil
}
func ParseJson( JsonStr string ) Book {
	var book Book
	json.Unmarshal( []byte(JsonStr) , &book )
	return book
}
func DownloadImage( SourceAddr string , AimFilename string) error {
	var file *os.File
	var err error
	if err != nil {
		return err
	}
	rsp, err := http.Get( SourceAddr )
	if err != nil {
		return err
	}
	defer rsp.Body.Close()

	contents, err := ioutil.ReadAll( rsp.Body )
	if err != nil {
		return err
	}
	file , err = os.Create( AimFilename )
	if err != nil {
		return err
	}
	defer file.Close()
	_ , err = file.Write( contents )
	if err != nil {
		return err
	}

	return nil
}
func SavePicture( book Book , AbsDir string ) error {
	IdStr := book.Id
	SmallImageFilename := AbsDir + "/Images/Small/" + IdStr + ".jpg"
	MediumImageFilename := AbsDir + "/Images/Medium/" + IdStr + ".jpg"
	LargeImageFilename := AbsDir + "/Images/Large/" + IdStr + ".jpg"

	var err error = nil
	for {
		err = DownloadImage( book.Images.Small , SmallImageFilename )
		if err != nil {
			break
		}
		err = DownloadImage( book.Images.Medium , MediumImageFilename )
		if err != nil {
			break
		}
		err = DownloadImage( book.Images.Large , LargeImageFilename )
		if err != nil {
			break
		}
		break
	}
	return err
}
func SaveToMysql( book Book , db *sql.DB ) error {
	for {
		// check if id existed
		cSql := "select id from t_book where id=" + book.Id
		rows , err := db.Query( cSql )
		if err != nil{
			return err
		}
		defer rows.Close()
		if rows.Next() {
			fmt.Print(" inserted before ")
			return nil
		}


		//save to t_book
		sql := `insert into t_book set
		subtitle=? ,
		pubdate=? ,
		origin_title=? ,
		image=? ,
		catalog=? ,
		pages=? ,
		alt=? ,
		ID=? ,
		publisher=? ,
		isbn10=? ,
		isbn13=? ,
		title=? ,
		url=? ,
		alt_title=? ,
		author_intro=? ,
		summary=? ,
		price=?
		`

		stmt , err := db.Prepare( sql )
		if err != nil {
			return err
		}
		res , err := stmt.Exec(
			book.Subtitle,
			book.Pubdate,
			book.Origin_title,
			book.Image,
			book.Catalog,
			book.Pages,
			book.Alt,
			book.Id,
			book.Publisher,
			book.Isbn10,
			book.Isbn13,
			book.Title,
			book.Url,
			book.Alt_title,
			book.Author_intro,
			book.Summary,
			book.Price)
		if err != nil {
			return err
		}
		r , _ := res.RowsAffected()
		if r>0 {
			fmt.Print(" inserted ")
		}

		// save to t_book_author
		for i:=0; i<len(book.Author) ;i++ {
			author := book.Author[i]
			sql = "insert into t_book_author set book_id=?, author=?"
			stmt , err = db.Prepare( sql )
			if err != nil {
				return err
			}
			_, err = stmt.Exec( book.Id , author )
			if err != nil {
				return err
			}
		}

		// save to t_book_translator
		for i:=0; i<len(book.Translator) ;i++ {
			translator := book.Translator[i]
			sql = "insert into t_book_translator set book_id=?, translator=?"
			stmt , err = db.Prepare( sql )
			if err != nil {
				return err
			}
			_, err = stmt.Exec( book.Id , translator )
			if err != nil {
				return err
			}
		}

		// save to t_book_rating
		sql = "insert into t_book_rating set book_id=?, max=?, numraters=?, average=?, min=?"
		stmt , err = db.Prepare( sql )
		if err != nil {
			return err
		}
		_, err = stmt.Exec( book.Id , book.Rating.Max, book.Rating.NumRaters , book.Rating.Average , book.Rating.Min )
		if err != nil {
			return err
		}

		// save to t_book_tags
		for i:=0; i<len(book.Tags) ;i++ {
			tag := book.Tags[i]
			sql = "insert into t_book_tags set book_id=?, count=?, name=?, title=?"
			stmt , err = db.Prepare( sql )
			if err != nil {
				return err
			}
			_, err = stmt.Exec( book.Id , tag.Count , tag.Name , tag.Title )
			if err != nil {
				return err
			}
		}

		//		stmt , err := db.Prepare("insert into t_book set ID=?, TITLE=?")
		//		if err != nil {
		//			fmt.Println( err )
		//			return err
		//		}
		//
		//		_ , err = stmt.Exec( 1001 , "阿凡客" )
		//		if err != nil {
		//			fmt.Println( err )
		//			return err
		//		}

		break
	}
	return nil
}
func GetBookFromDB( bookId string , db *sql.DB ) ( publicClass.Reason ) {
	result := publicClass.Reason{ true , "" , nil }
	book := Book{}
	var err error = nil
	isBook := true
FirstLoop:
	for {
		// get main info
		sql := `select
		title,
		subtitle,
		pubdate,
		origin_title,
		image,
		catalog,
		pages,
		alt,
		publisher,
		isbn10,
		isbn13,
		url,
		alt_title,
		author_intro,
		summary,
		price
		from t_book where id = ` + bookId

		rows , err := db.Query( sql  )
		if err != nil {
			break
		}
		defer rows.Close()
		if rows.Next() {
			var title        string
			var subtitle     string
			var pubdate      string
			var origin_title string
			var image        string
			var catalog      string
			var pages        string
			//		var small_image  string
			//		var medium_image string
			//		var large_image  string
			var alt          string
			var publisher    string
			var isbn10       string
			var isbn13       string
			var url          string
			var alt_title    string
			var author_intro string
			var summary      string
			var price        string
			//		err = rows.Scan( &title , &subtitle , &pubdate , &origin_title ,&image, &catalog , &pages)
			err = rows.Scan( &title , &subtitle , &pubdate , &origin_title ,
				&image , &catalog , &pages ,  &alt, &publisher ,
				&isbn10, &isbn13, &url, &alt_title, &author_intro,
				&summary, &price)
			if err != nil {
				break
			}
			book.Title         = title
			book.Subtitle      = subtitle
			book.Pubdate       = pubdate
			book.Origin_title  = origin_title
			book.Image         = image
			book.Catalog       = catalog
			book.Pages         = pages
			//		book.Images.Small  = small_image
			//		book.Images.Medium = medium_image
			//		book.Images.Large  = large_image
			book.Alt           = alt
			book.Publisher     = publisher
			book.Isbn10        = isbn10
			book.Isbn13        = isbn13
			book.Url           = url
			book.Alt_title     = alt_title
			book.Author_intro  = author_intro
			book.Summary       = summary
			book.Price         = price
		}else {
			fmt.Println("is not a book")
			isBook = false
			result.Reason += "this is not a book"
			break
		}

		//get authors info
		authors := []string{}
		sql = "select author from t_book_author where book_id = " + bookId
		rows , err = db.Query( sql )
		if err != nil {
			break
		}
		for rows.Next() {
			var author string
			err = rows.Scan( &author )
			if err != nil {
				break FirstLoop
			}
			authors = append( authors , author )
		}
		book.Author = authors

		// get translators info
		translators := []string{}
		sql = "select translator from t_book_translator where book_id = " + bookId
		rows , err = db.Query( sql )
		if err != nil {
			break
		}
		for rows.Next() {
			var translator string
			err = rows.Scan( &translator )
			if err != nil {
				break FirstLoop
			}
			translators = append( translators , translator )
		}
		book.Translator = translators

		// get rating info
		rating := Rating{}
		sql = "select max,numraters,average,min from t_book_rating where book_id = " + bookId
		rows , err = db.Query( sql )
		if err != nil {
			break
		}
		if rows.Next() {
			err = rows.Scan( &rating.Max , &rating.NumRaters , &rating.Average , &rating.Min)
			if err != nil {
				break
			}
		}
		book.Rating = rating

		// get tags info
		tags := []Tag{}
		sql = "select count,name,title from t_book_tags where book_id = " + bookId
		rows , err = db.Query( sql )
		if err != nil {
			break
		}
		for rows.Next() {
			var tag Tag
			err = rows.Scan( &tag.Count , &tag.Name , &tag.Title )
			if err != nil {
				break FirstLoop
			}
			tags = append( tags , tag )
		}
		book.Tags = tags
	}
	result.Data = book
	if err != nil {
		result.IsSuccess = false
		result.Reason += err.Error()
		result.Data = ""
	}
	if !isBook {
		result.IsSuccess = false
		result.Data = ""
	}

	return result
}




